package com.opennews.openplatform.controller;

import com.opennews.openplatform.common.constant.IncomeExpenseTypeConstant;
import com.opennews.openplatform.common.constant.PaymentTypeConstant;
import com.opennews.openplatform.myspringbootcore.dto.ApiResponse;
import com.opennews.openplatform.myspringbootcore.util.SharedUtil;
import com.opennews.openplatform.myspringbootmvccore.helper.HttpResponseHelper;
import com.opennews.openplatform.myspringbootmvccore.security.RequestIdentityExtractor;
import com.opennews.openplatform.service.IncomeExpenseAnalysisService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RequiredArgsConstructor
@RestController
@RequestMapping("/income-expense-analysis")
public class IncomeExpenseAnalysisController {
    private final IncomeExpenseAnalysisService incomeExpenseAnalysisService;
    private final RequestIdentityExtractor requestIdentityExtractor;
    private final HttpResponseHelper httpResponseHelper;

    @GetMapping("/query-existing-distinct-years")
    public ResponseEntity<ApiResponse<List<Integer>>> queryExistingDistinctYears() {
        String accountGroupId = requestIdentityExtractor.getClaims().accountGroupId;
        List<Integer> result = incomeExpenseAnalysisService.queryExistingDistinctYears(accountGroupId);

        return httpResponseHelper.getSuccessResponse(result);
    }

    @GetMapping("/query-summary-by-existing-years")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> querySummaryByExistingYears() {
        String accountGroupId = requestIdentityExtractor.getClaims().accountGroupId;
        List<Integer> years = incomeExpenseAnalysisService.queryExistingDistinctYears(accountGroupId);
        List<Map<String, Object>> result = incomeExpenseAnalysisService.queryAnnualSummaryByYears(accountGroupId, years);

        return httpResponseHelper.getSuccessResponse(result);
    }

    @GetMapping("/query-overall-summary")
    public ResponseEntity<ApiResponse<Map<String, Map<String, Object>>>> queryOverallSummary() {
        String accountGroupId = requestIdentityExtractor.getClaims().accountGroupId;
        Map<String, Map<String, Object>> result = incomeExpenseAnalysisService.queryOverallSummary(accountGroupId);

        return httpResponseHelper.getSuccessResponse(result);
    }

    @GetMapping("/query-annual-monthly-summary")
    public ResponseEntity<ApiResponse<Map<String, Object>>> queryAnnualMonthlySummary(@RequestParam int year) {
        String accountGroupId = requestIdentityExtractor.getClaims().accountGroupId;
        Map<String, Object> cashIncomeSummary = incomeExpenseAnalysisService.queryAnnualMonthlySummary(accountGroupId, IncomeExpenseTypeConstant.INCOME, PaymentTypeConstant.CASH, year);
        Map<String, Object> cashExpenseSummary = incomeExpenseAnalysisService.queryAnnualMonthlySummary(accountGroupId, IncomeExpenseTypeConstant.EXPENSE, PaymentTypeConstant.CASH, year);
        Map<String, Object> creditCardIncomeSummary = incomeExpenseAnalysisService.queryAnnualMonthlySummary(accountGroupId, IncomeExpenseTypeConstant.INCOME, PaymentTypeConstant.CREDIT_CARD, year);
        Map<String, Object> creditCardExpenseSummary = incomeExpenseAnalysisService.queryAnnualMonthlySummary(accountGroupId, IncomeExpenseTypeConstant.EXPENSE, PaymentTypeConstant.CREDIT_CARD, year);

        return httpResponseHelper.getSuccessResponse(Map.of(
                "cashIncomeSummary", cashIncomeSummary,
                "cashExpenseSummary", cashExpenseSummary,
                "creditCardIncomeSummary", creditCardIncomeSummary,
                "creditCardExpenseSummary", creditCardExpenseSummary
        ));
    }

    @GetMapping("/query-monthly-daily-summary")
    public ResponseEntity<ApiResponse<Map<String, Object>>> queryMonthlyDailySummary(@RequestParam int year, @RequestParam int month) {
        String accountGroupId = requestIdentityExtractor.getClaims().accountGroupId;
        Map<String, Object> cashIncomeSummary = incomeExpenseAnalysisService.queryMonthlyDailySummary(accountGroupId, IncomeExpenseTypeConstant.INCOME, PaymentTypeConstant.CASH, year, month);
        Map<String, Object> cashExpenseSummary = incomeExpenseAnalysisService.queryMonthlyDailySummary(accountGroupId, IncomeExpenseTypeConstant.EXPENSE, PaymentTypeConstant.CASH, year, month);
        Map<String, Object> creditCardIncomeSummary = incomeExpenseAnalysisService.queryMonthlyDailySummary(accountGroupId, IncomeExpenseTypeConstant.INCOME, PaymentTypeConstant.CREDIT_CARD, year, month);
        Map<String, Object> creditCardExpenseSummary = incomeExpenseAnalysisService.queryMonthlyDailySummary(accountGroupId, IncomeExpenseTypeConstant.EXPENSE, PaymentTypeConstant.CREDIT_CARD, year, month);

        return httpResponseHelper.getSuccessResponse(Map.of(
                "cashIncomeSummary", cashIncomeSummary,
                "cashExpenseSummary", cashExpenseSummary,
                "creditCardIncomeSummary", creditCardIncomeSummary,
                "creditCardExpenseSummary", creditCardExpenseSummary
        ));
    }

    @GetMapping("/query-top-rank-by-account-group")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> queryTopRankByAccountGroup(
            @RequestParam String type,
            @RequestParam String paymentType,
            @RequestParam(required = false) String year,
            @RequestParam(required = false) String month,
            @RequestParam int pageSize,
            @RequestParam int pageIndex) throws MissingServletRequestParameterException {
        String accountGroupId = requestIdentityExtractor.getClaims().accountGroupId;
        Integer yearValue = validateIntegerValue("year", year);
        Integer monthValue = validateIntegerValue("month", month);
        List<Map<String, Object>> result = incomeExpenseAnalysisService.queryTopRankByAccountGroup(accountGroupId, pageSize, pageIndex, type, paymentType, yearValue, monthValue);

        return httpResponseHelper.getSuccessResponse(result);
    }

    @GetMapping("/query-summary-by-detail-type")
    public ResponseEntity<ApiResponse<List<Map<String, Object>>>> querySummaryByDetailType(
            @RequestParam String type,
            @RequestParam String paymentType,
            @RequestParam(required = false) String year,
            @RequestParam(required = false) String month) throws MissingServletRequestParameterException {
        String accountGroupId = requestIdentityExtractor.getClaims().accountGroupId;
        Integer yearValue = validateIntegerValue("year", year);
        Integer monthValue = validateIntegerValue("month", month);

        List<Map<String, Object>> result = type.equals(IncomeExpenseTypeConstant.EXPENSE) ? incomeExpenseAnalysisService.queryExpenseByDetailType(accountGroupId, paymentType, yearValue, monthValue)
                : incomeExpenseAnalysisService.queryIncomeByDetailType(accountGroupId, paymentType, yearValue, monthValue);

        return httpResponseHelper.getSuccessResponse(result);
    }

    private Integer validateIntegerValue(String strName, String strValue) throws MissingServletRequestParameterException {
        Integer integerValue = null;

        // Manually validate the parameter.
        if (strValue != null && !SharedUtil.isNullOrEmpty(strValue)) {
            try {
                integerValue = Integer.parseInt(strValue);
            } catch (NumberFormatException e) {
                throw new MissingServletRequestParameterException(strName, String.format("Invalid %s format. Must be an integer.", strName));
            }
        }

        return integerValue;
    }
}
